package xdb

import (
	"context"
	"fmt"
	"gitee.com/go-mid/infra/xconfig"
	"gitee.com/go-mid/infra/xlog"
	"gitee.com/go-mid/infra/xobserver"
	"gitee.com/go-mid/infra/xsql/sqlconf"
	"sync"
)

// Manager 管理数据库实例和连接池
type Manager struct {
	center     xconfig.ConfigCenter
	clusterMgr *InstanceManager
	// 动态配置
	sqlconfs  map[string]*sqlconf.MysqlConf
	namespace string
	sync.Mutex
}

var defaultMysqlNamespace = "mysql"

//NewManager 实例化DB路由对象
func NewManager(center xconfig.ConfigCenter, namespace string) (*Manager, error) {
	mgr := &Manager{
		center: center,
	}
	if namespace == "" {
		namespace = defaultMysqlNamespace
	}
	mgr.namespace = namespace
	mgr.reloadConfig()
	mgr.observer(context.Background())
	return mgr, nil
}

func (m *Manager) reloadConfig() error {
	m.Lock()
	defer m.Unlock()
	var confs = make(map[string]*sqlconf.MysqlConf)
	err := m.center.Unmarshal(context.Background(), m.namespace, &confs)
	if err != nil {
		return err
	}
	m.sqlconfs = confs
	factory := func(make map[string]*sqlconf.MysqlConf) func(ctx context.Context, cluster string) (in Instancer, err error) {
		return func(ctx context.Context, cluster string) (in Instancer, err error) {
			if sqlcfg, ok := confs[cluster]; ok {
				return factory(ctx, cluster, sqlcfg)
			}
			return nil, err
		}
	}(confs)
	m.clusterMgr = NewInstanceManager(factory)
	return nil
}

// GetDB return manager.DB without transaction
func (m *Manager) GetDB(ctx context.Context, cluster string) (*DB, error) {
	instance, err := m.getInstance(ctx, cluster)
	if err != nil {
		xlog.Warnf(ctx, "not config db: %s, try default", cluster)
		instance, err = m.getInstance(ctx, "default")
		if err != nil {
			xlog.Warnf(ctx, "not config default db : %s", cluster)
			return nil, err
		}
	}
	db := new(DB)
	db.cluster = cluster
	db.db = instance.db
	return db, nil
}

// IgnoreTableNameCheck ignore check table name rule
func (m *Manager) IgnoreTableNameCheck() {
	bCheckTableName = false
}

//获取DB实例
func (m *Manager) getInstance(ctx context.Context, instance string) (dbInstance *DBInstance, err error) {
	in := m.clusterMgr.Get(ctx, instance)
	if in == nil {
		err = fmt.Errorf("db instance not find: instance:%s", instance)
		return nil, err
	}

	dbInstance, ok := in.(*DBInstance)
	if !ok {
		err = fmt.Errorf("db instance type error: instance:%s ", instance)

		return nil, err
	}
	return dbInstance, err
}

func (m *Manager) observer(ctx context.Context) error {
	m.center.RegisterObserver(ctx, m.namespace, xobserver.NewConfigObserver(func(ctx context.Context, event *xobserver.ChangeEvent) {
		//全部监听到，全部关闭
		m.clusterMgr.Close()
		err := m.reloadConfig()
		if err != nil {
			xlog.Errorf(ctx, "reload db config error: %v", err)
			return
		}
		xlog.Infof(ctx, "reload db config")
	}))
	return nil
}
